package com.hzyl.famousreader.view.widget.core.loader;

import android.support.annotation.Nullable;
import com.blankj.utilcode.util.*;
import com.hzyl.famousreader.view.widget.core.Charset;
import com.hzyl.famousreader.view.widget.core.PageView;
import com.hzyl.famousreader.view.widget.core.model.Chapter;
import com.hzyl.famousreader.view.widget.core.model.Page;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

public abstract class DataLoader {

  protected static final int DEFAULT_MARGIN_HEIGHT = 28;
  protected static final int DEFAULT_MARGIN_WIDTH = 12;
  //书籍绘制区域的宽高
  protected int mVisibleWidth;
  protected int mVisibleHeight;
  //应用的宽高
  protected int mDisplayWidth;
  protected int mDisplayHeight;
  //间距
  protected int mMarginWidth = ConvertUtils.dp2px(DEFAULT_MARGIN_WIDTH);
  protected int mMarginHeight = ConvertUtils.dp2px(DEFAULT_MARGIN_HEIGHT);

  /**
   * 书籍视图
   */
  private PageView mView;

  ////////////////////////////////////////////////////////////////////////
  //  核心参数
  ////////////////////////////////////////////////////////////////////////
  /**
   * 是否准备好
   */
  protected boolean isPrepare = false;

  /**
   * 当前页面加载状态
   */
  protected DataLoaderStatusEnum curLoaderStatus = DataLoaderStatusEnum.LOADING;

  /**
   * 当前章节位置
   */
  protected int curChapterPos = 0;

  /**
   * 当前章节书页位置
   */
  protected int curChapterPagePos = 0;

  ///////////////////////////////////////////////////////////////////////
  // 书页信息
  ///////////////////////////////////////////////////////////////////////
  /**
   * 文件的编码类型
   */
  protected Charset mCharset;

  /**
   * 当前章节列表
   */
  protected List<Chapter> chapters;

  /**
   * 上一章的页面列表缓存
   */
  private WeakReference<List<Page>> mWeakPrePageList;

  /**
   * 当前章节的页面列表
   */
  private List<Page> curPages;

  /**
   * 下一章的页面列表缓存
   */
  private List<Page> nextPages;

  /**
   * 当前显示的页
   */
  private Page curPage;

  /**
   * 翻页监听器
   */
  protected OnPageChangeListener listener;

  ///////////////////////////////////////////////////////////////////////
  //  参数设置区
  ///////////////////////////////////////////////////////////////////////
  /**
   * 设置view
   */
  public void setPageView(PageView pageView) {
    this.mView = pageView;
  }

  /**
   * 设置监听器
   * @param listener
   */
  public void setOnPageChangeListener(OnPageChangeListener listener) {
    this.listener = listener;
  }

  ///////////////////////////////////////////////////////////////////////
  //  参数获取区
  ///////////////////////////////////////////////////////////////////////
  /**
   * 获取当前Loader的状态
   */
  public DataLoaderStatusEnum getLoadStatus() {
    return curLoaderStatus;
  }

  /**
   * 获取章节
   * @return
   */
  public List<Chapter> getChapters() {
    return chapters;
  }

  /**
   * 当前章节的标题
   */
  public String getChapterTitle() {
    return chapters.get(curChapterPos).getTitle();
  }

  /**
   * 当前章节的页数
   */
  public int getCurPagesSize() {
    return curPages.size();
  }

  /**
   * 获取当前书页
   * @return
   */
  public Page getCurPage() {
    return curPage;
  }

  /**
   * 获取书页位置
   * @return
   */
  public int getCurPagePosition() {
    return curPage.getPosition() + 1;
  }

  ///////////////////////////////////////////////////////////////////////
  //  功能区
  ///////////////////////////////////////////////////////////////////////
  /**
   * 初始化
   */
  public void init() {
    if(!isPrepare && mVisibleHeight > 0 && mVisibleWidth > 0) {
      isPrepare = true;
      skipToChapter(this.curChapterPos);
      mView.invalidate();
    }
  }

  public void notifyChapterIsExit(int chapter) {
    if(chapter == curChapterPos && curLoaderStatus == DataLoaderStatusEnum.LOADING) {
      LogUtils.d("是改章节啦，刷新刷新刷新");
      reload();
      mView.invalidate();
    }
  }

  /**
   * 适应调整视图大小
   *
   * @param w
   * @param h
   */
  public void onSizeChange(int w, int h) {
    //获取PageView的宽高
    mDisplayWidth = w;
    mDisplayHeight = h;

    //获取内容显示位置的大小
    mVisibleWidth = mDisplayWidth - mMarginWidth * 2;
    mVisibleHeight = mDisplayHeight - mMarginHeight * 2;

    //如果章节已显示，那么就重新计算页面
    if (curLoaderStatus == DataLoaderStatusEnum.FINISH) {
      curPages = loadChapterContent(curChapterPos);
      //重新设置文章指针的位置
      if(curPages == null) {
        listener.chapterNotFound(curChapterPos);
      } else {
        curPage = curPages.get(curPage==null? 0:curPage.getPosition());
      }
    } else {
      init();
    }
  }

  /**
   * 参数改变，重新加载章节内容数据
   */
  public void reload() {
    //取消缓存
    mWeakPrePageList = null;
    nextPages = null;

    //重新计算页面
    curPages = loadChapterContent(curChapterPos);

    if(curPage == null) {
      curPage = curPages.get(curChapterPagePos);
    } else if (curPage.getPosition() >= curPages.size()) {
      //防止在最后一页，通过修改字体，以至于页面数减少导致崩溃的问题
      curPage.setPosition(curPages.size() - 1);
    }
    //重新设置文章指针的位置
    curPage = curPages.get(curPage.getPosition());

    curLoaderStatus = DataLoaderStatusEnum.FINISH;
  }

  /**
   * 跳转到上一章
   */
  public boolean prevChapter() {
    boolean canPrev = loadPrevChapter();
    if (canPrev) {
      if(curLoaderStatus == DataLoaderStatusEnum.FINISH) {
        curPage = curPages.get(0);
        invokePageChangeListener();
      }
    }
    return canPrev;
  }

  /**
   * 跳转到下一章
   */
  public boolean nextChapter() {
    boolean canNext = loadNextChapter();
    if (canNext) {
      if(curLoaderStatus == DataLoaderStatusEnum.FINISH) {
        curPage = curPages.get(0);
        invokePageChangeListener();
      }
    }

    return canNext;
  }

  /**
   * 跳转到指定章节
   *
   * @param pos 目标章节
   */
  public void skipToChapter(int pos) {
    //正在加载
    curLoaderStatus = DataLoaderStatusEnum.LOADING;
    //绘制当前的状态
    curChapterPos = pos;
    //将上一章的缓存设置为null
    mWeakPrePageList = null;

    //将下一章缓存设置为null
    nextPages = null;

    if (curPage != null) {
      //重置position的位置，防止正在加载的时候退出时候存储的位置为上一章的页码
      curPage.setPosition(0);
    }

    curPages = loadChapterContent(curChapterPos);
    if(curPages == null) {
      listener.chapterNotFound(curChapterPos);
      return;
    }
    //进行预加载
    preLoadNextChapter();
    //加载完成
    curLoaderStatus = DataLoaderStatusEnum.FINISH;

    curPage = curPages.get(curChapterPagePos);

    invokePageChangeListener();
  }

  /**
   * 跳转到上一页
   *
   * @return true-可以往前翻，false-第一页
   */
  public boolean prevPage() {
    if (isLoading()) {
      mWeakPrePageList = null;
      return prevChapter();
    }

    //判断是否达到章节的起始点
    Page prevPage = getPrevPage();
    if (prevPage == null) {
      //载入上一章。
      if(loadPrevChapter()) {
        if(curLoaderStatus == DataLoaderStatusEnum.FINISH) {
          curPage = curPages.get(curPages.size() - 1);
        }
      } else {
        return false;
      }
    } else {
      curPage = prevPage;
    }

    invokePageChangeListener();

    return true;
  }

  /**
   * 往后翻页
   *
   * @return true-可以往后翻，false-最后一页
   */
  public boolean nextPage() {
    if (isLoading()) {
      return nextChapter();
    }

    //判断是否到最后一页了
    Page nextPage = getNextPage();
    if (nextPage == null) {
      if(loadNextChapter()) {
        if(curLoaderStatus == DataLoaderStatusEnum.FINISH) {
          curPage = curPages.get(0);
        }
      } else {
        //已经是最后一章了
        return false;
      }
    } else {
      curPage = nextPage;
    }

    invokePageChangeListener();

    return true;
  }

  ///////////////////////////////////////////////////////////////////////
  //  工作区
  ///////////////////////////////////////////////////////////////////////
  /**
   * 加载上一章
   *
   * @return true-加载成功 false-已经是第一张，无法加载
   */
  protected boolean loadPrevChapter() {
    //判断是否上一章节为空
    if (curChapterPos - 1 < 0) {
      ToastUtils.showShort("已经没有上一章了");
      return false;
    }

    //正在加载数据
    curLoaderStatus = DataLoaderStatusEnum.LOADING;

    //加载上一章数据
    int prevChapter = curChapterPos - 1;
    //当前章变成下一章
    nextPages = curPages;

    //判断上一章缓存是否存在，如果存在则从缓存中获取数据。
    if (mWeakPrePageList != null && mWeakPrePageList.get() != null) {
      curPages = mWeakPrePageList.get();
      mWeakPrePageList = null;
    }
    //如果不存在则加载数据
    else {
      curPages = loadChapterContent(prevChapter);
    }

    curChapterPos = prevChapter;

    if (curPages != null) {
      curLoaderStatus = DataLoaderStatusEnum.FINISH;
    }
    //如果当前章不存在，则表示在加载中
    else {
      curLoaderStatus = DataLoaderStatusEnum.LOADING;
      //重置position的位置，防止正在加载的时候退出时候存储的位置为上一章的页码
      curPage.setPosition(0);

      listener.chapterNotFound(prevChapter);
    }

    return true;
  }

  /**
   * 加载下一章的内容
   *
   * @return true-加载成功 false-已经是最后一章了，无法加载
   */
  protected boolean loadNextChapter() {
    //加载一章
    if (curChapterPos + 1 >= chapters.size()) {
      ToastUtils.showShort("已经没有下一章了");
      return false;
    }

    //正在加载数据
    curLoaderStatus = DataLoaderStatusEnum.LOADING;

    //存储当前Page列表为上一章
    if (curPages != null) {
      mWeakPrePageList = new WeakReference<>(new ArrayList<>(curPages));
    }

    int nextChapter = curChapterPos + 1;
    //如果存在下一章预加载章节。
    if (nextPages != null) {
      curPages = nextPages;
      nextPages = null;
    } else {
      //这个PageList可能为 null，可能会造成问题。
      curPages = loadChapterContent(nextChapter);
    }

    curChapterPos = nextChapter;

    //如果存在当前章，预加载下一章
    if (curPages != null) {
      curLoaderStatus = DataLoaderStatusEnum.FINISH;
      preLoadNextChapter();
    }
    //如果当前章不存在，则表示在加载中
    else {
      curLoaderStatus = DataLoaderStatusEnum.LOADING;
      //重置position的位置，防止正在加载的时候退出时候存储的位置为上一章的页码
      curPage.setPosition(0);
      listener.chapterNotFound(nextChapter);
    }

    return true;
  }

  /**
   * 预加载下一章
   */
  protected void preLoadNextChapter() {
    //判断是否存在下一章
    int nextChapter = curChapterPos + 1;
    if (nextChapter >= chapters.size()) {
      return;
    }

    ThreadUtils.executeByIo(new ThreadUtils.SimpleTask<List<Page>>() {
      @Nullable
      @Override
      public List<Page> doInBackground() throws Throwable {
        return loadChapterContent(nextChapter);
      }

      @Override
      public void onSuccess(@Nullable List<Page> result) {
        nextPages = result;
      }
    });
  }

  /**
   * @return:获取上一个页面
   */
  protected Page getPrevPage() {
    int pos = curPage.getPosition() - 1;
    if (pos < 0) {
      return null;
    }

    return curPages.get(pos);
  }

  /**
   * @return:获取下一页面
   */
  protected Page getNextPage() {
    if (curPage != null) {
      int pos = curPage.getPosition() + 1;
      if (pos >= curPages.size()) {
        return null;
      }

      return curPages.get(pos);
    }
    return new Page();
  }

  /**
   * 检测当前状态是否能够进行加载章节数据
   *
   * @return
   */
  protected boolean isLoading() {
    boolean isLoading = curLoaderStatus == DataLoaderStatusEnum.LOADING;
    if(isLoading) {
      ToastUtils.showShort("正在加载中，请稍等");
    }
    return isLoading;
  }

  ///////////////////////////////////////////////////////////////////////
  //  核心方法
  ///////////////////////////////////////////////////////////////////////
  /**
   * 打开章节的数据流
   * @param chapter
   * @return
   */
  protected abstract BufferedReader openChapter(Chapter chapter) throws IOException;

  /**
   * 加载章节内容
   * @param position
   * @return
   */
  private List<Page> loadChapterContent(int position) {
    return loadChapterContent(chapters.get(position));
  }

  /**
   * 加载章节内容
   * @param chapter
   * @return
   */
  private List<Page> loadChapterContent(Chapter chapter){
    try (BufferedReader br = openChapter(chapter)) {
      //生成的页面
      List<Page> pages = new ArrayList<>();

      //使用流的方式加载
      List<String> lines = new ArrayList<>();
      int rHeight = mVisibleHeight; //由于匹配到最后，会多删除行间距，所以在这里多加个行间距
      int titleLinesCount = 0;
      boolean isTitle = true; //不存在没有 Title 的情况，所以默认设置为 true。
      String paragraph = chapter.getTitle();//默认展示标题
        while (isTitle || (paragraph = br.readLine()) != null) {

          //重置段落
          if (!isTitle) {
            paragraph = paragraph.replaceAll("\\s", "");
            //如果只有换行符，那么就不执行
            if (paragraph.equals("")) continue;
            paragraph = StringUtils.toSBC("  " + paragraph + "\n");
          } else {
            //设置 title 的顶部间距
            rHeight -= mView.mTitlePara;
          }

          int wordCount = 0;
          String subStr = null;
          while (paragraph.length() > 0) {
            //当前空间，是否容得下一行文字
            if (isTitle) {
              rHeight -= mView.mTitlePaint.getTextSize();
            } else {
              rHeight -= mView.mTextPaint.getTextSize();
            }

            //一页已经填充满了，创建 TextPage
            if (rHeight < 0) {
              //创建Page
              Page page = new Page();
              page.setPosition(pages.size());
              page.setLines(new ArrayList<>(lines));
              page.setTitle(chapter.getTitle());
              page.setTitleLines(titleLinesCount);
              pages.add(page);
              //重置Lines
              lines.clear();
              rHeight = mVisibleHeight;
              titleLinesCount = 0;
              continue;
            }

            //测量一行占用的字节数
            if (isTitle) {
              wordCount = mView.mTitlePaint.breakText(paragraph, true, mVisibleWidth, null);
            } else {
              wordCount = mView.mTextPaint.breakText(paragraph, true, mVisibleWidth, null);
            }

            subStr = paragraph.substring(0, wordCount);
            if (!subStr.equals("\n")) {
              //将一行字节，存储到lines中
              lines.add(subStr);

              //设置段落间距
              if (isTitle) {
                titleLinesCount += 1;
                rHeight -= mView.mTitleInterval;
              } else {
                rHeight -= mView.mTextInterval;
              }
            }
            //裁剪
            paragraph = paragraph.substring(wordCount);
          }

          //增加段落的间距
          if (!isTitle && lines.size() != 0) {
            rHeight = rHeight - mView.mTextPara + mView.mTextInterval;
          }

          if (isTitle) {
            rHeight = rHeight - mView.mTitlePara + mView.mTitleInterval;
            isTitle = false;
          }
        }

        if (lines.size() != 0) {
          //创建Page
          Page page = new Page();
          page.setPosition(pages.size());
          page.setLines(new ArrayList<>(lines));
          page.setTitle(chapter.getTitle());
          page.setTitleLines(titleLinesCount);
          pages.add(page);
          //重置Lines
          lines.clear();
        }


      //可能出现内容为空的情况
      if (pages.size() == 0) {
        Page page = new Page();
        page.setLines(new ArrayList<>(1));
        pages.add(page);
       }

      return pages;
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }

    return null;
  }

  ////////////////////////////////////////////////////////////////////
  //  事件监听器
  ////////////////////////////////////////////////////////////////////
  /**
   * 翻页接口
   */
  public interface OnPageChangeListener {
    /**
     * 当前的章节和对应的页码
     * @param chapter
     * @param page
     */
    void pageChange(int chapter, int page);

    void chapterNotFound(int chapter);
  }

  /**
   * 调用书页变更的监听器
   */
  private void invokePageChangeListener() {
    if(listener != null) {
      listener.pageChange(curChapterPos, curPage.getPosition());
    }
  }
}
